package com.book.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.book.domain.LoginUser;
import com.book.dto.UserDto;
import com.book.dao.UserDao;
import com.book.utils.ResponseResult;
import com.book.entity.User;
import com.book.service.LoginService;
import com.book.utils.RedisCache;
import com.book.utils.UniqueCodeGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
//用户方面的错误为1001开头
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private UserDao userDao;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public ResponseResult login(UserDto user) {
        //AuthenticationManager authenticate进行用户认证,先在配置类里面配置bean，这样就可以进行上面的autowired（第一个）
        //获取用户认证管理器
        //验证验证码,如果redis中这个邮箱对应的验证码为Null,或者取出来的验证码跟输入的验证码不一样，就直接返回。
//        System.out.println(user);
        if (redisCache.getCacheObject(user.getEmail())==null ||
                !redisCache.getCacheObject(user.getEmail()).equals(user.getCaptcha()))
            return new ResponseResult(1001,"验证码不正确或失效！");

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getEmail(),user.getPassword());
        //获取认证管理器，如果认证成功那么会需要将用户认证信息存入security认证管理器中，并由系统自动生成认证管理器
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //如果认证没通过，给出对应的提示
        if(Objects.isNull(authenticate)){
            return new ResponseResult(1007,"登录失败");
        }

        //如果认证通过，使用userid存入ResponseResult返回。
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();//里面获取数据库的用户数据
        if(loginUser.getUser().getStatus()==1){
            return new ResponseResult(1008,"该账号已被管理员设置暂停登录，请更换账号重新登录。");
        }

        String userid = loginUser.getUser().getId();
        String head = loginUser.getUser().getHead();

        Map<String, Object> map = new HashMap<>();//把userId传给前端
//        String jwt = JwtUtil.createJWT(userid);//突然发现没必要用token
//        map.put("token",jwt);//突然发现没必要用token
        map.put("userId",userid);
        map.put("head",head);
        //把完整的用户信息存入redis,userid作为key
        //todo 记得到时候调回来
//        redisCache.setCacheObject("login:"+userid,loginUser,30, TimeUnit.DAYS);//登录信息保存30天，开发阶段不用这个
        redisCache.setCacheObject("login:"+userid,loginUser);//开发阶段用这个,不设置过期时间
        //向前端返回jwt
        return new ResponseResult(200,"登录成功",map);
    }

    /**
     * 管理员登录
     * @param user
     * @return
     */
    @Override
    public ResponseResult loginAdmin(UserDto user) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getEmail(),user.getPassword());
        //获取认证管理器，如果认证成功那么会需要将用户认证信息存入security认证管理器中，并由系统自动生成认证管理器
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //如果认证没通过，给出对应的提示
        if(Objects.isNull(authenticate)){
            return new ResponseResult(1000,"登录失败");
        }
        //如果认证通过，使用userid存入ResponseResult返回。
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();//里面获取数据库的用户数据
        if(loginUser.getUser().getUserType()==1){
            return new ResponseResult(1010,"您不是管理员，请立即停止登录!");
        }
        String userid = loginUser.getUser().getId();
        String head = loginUser.getUser().getHead();
        Map<String, Object> map = new HashMap<>();//把userId传给前端
        map.put("userId",userid);
        map.put("head",head);
//        redisCache.setCacheObject("login:"+userid,loginUser,30, TimeUnit.DAYS);//登录信息保存30天，开发阶段不用这个
        redisCache.setCacheObject("login:"+userid,loginUser);//开发阶段用这个,不设置过期时间
        return new ResponseResult(200,"登录成功",map);
    }

    @Override
    public ResponseResult logout(String userId) {
        try {
            //获取SecurityContextHolder中的用户id
            Authentication authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            String userid = loginUser.getUser().getId();
            //删除redis中的值
            if(userid.equals(userId)){
                redisCache.deleteObject("login:"+userid);
                return new ResponseResult(200,"注销成功");
            }
            return new ResponseResult(1002,"退出登陆失败！");
        }catch (Exception e){
            e.printStackTrace();
            return new ResponseResult(1003,"退出登陆失败！");
        }
    }
    

    @Override
    public ResponseResult register(UserDto user) {
        if (redisCache.getCacheObject(user.getEmail())==null ||
                !redisCache.getCacheObject(user.getEmail()).equals(user.getCaptcha()))
            return new ResponseResult(1004,"验证码不正确或失效！");

        //判断注册的邮箱是否重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",user.getEmail());
        if(!Objects.isNull(userDao.selectOne(queryWrapper))){
            return new ResponseResult(1005,"邮箱账号已存在，请直接登录！");
        }
        //重新封装一下注册的信息
        User user1 = new User();
        user1.setId(UniqueCodeGenerator.generateUniqueCode());
        user1.setEmail(user.getEmail());
        user1.setNickName("热爱生活");//默认昵称
        user1.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        user1.setSex(user.getSex());//几个字段，是默认的，不用写
        try {
            userDao.insert(user1);
            return new ResponseResult(200,"注册成功，快去登录吧");
        }catch (Exception e){
            return new ResponseResult(1006,"注册失败！");
        }
    }
}
